package com.kfm.login.controller;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.kfm.login.domain.SysUser;
import com.kfm.login.service.SysUserService;
import com.kfm.login.util.*;
import com.wf.captcha.SpecCaptcha;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.concurrent.TimeUnit;

@RestController
@Slf4j
public class LoginController {

    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private SysUserService sysUserService;

    @GetMapping("/")
    public ModelAndView indexPage(){
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.setViewName("redirect:/login");
        return modelAndView;
    }

    @GetMapping({ "/login"})
    public ModelAndView loginPage(){
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.setViewName("login");
        return modelAndView;
    }

    @PostMapping("/login")
    public Resp login(@RequestBody SysUser sysUser, @CookieValue(value = Constant.TOKEN_KEY, required = false) String token, HttpServletResponse response) throws Exception {
        log.info(sysUser.toString());
        // 判断用户名是手机号还是邮箱
        String username = sysUser.getUsername();
        String type = userNameType(username);

        // 密码加密
        String newPass = AesUtil.AES_CBC_Encrypt_String(sysUser.getPassword());

        // 数据库查询
        QueryWrapper<SysUser> queryWrapper = new QueryWrapper<>();
        queryWrapper.select("id", "username", "phone", "password", "email", "state");
        queryWrapper.eq(type, username);
        queryWrapper.eq("password", newPass);

        SysUser one = sysUserService.getOne(queryWrapper);

        if (one == null){
            return Resp.error("用户名或密码错误");
        } else {
            // 登录成功
            // 判断是否记住我?
            if (sysUser.getRememberMe() != null && sysUser.getRememberMe()){
                // 记住我
                // 存入 redis
//                redisTemplate.opsForValue().set(Constant.REMEMBER_USER_PRE + one.getId(), one, 7, TimeUnit.DAYS);
                // 存入 cookie
                String cookieValue = AesUtil.AES_CBC_Encrypt_String(one.getUsername()) + "--" + newPass;
                Cookie cookie = new Cookie(Constant.REMEMBER_ME, cookieValue);
                cookie.setPath("/login");
                cookie.setMaxAge(7 * 24 * 60 * 60);
                response.addCookie(cookie);
            }

            // TODO 是否异地登录

            // TODO 更新登录时间及登录地点

            // 生成 jwt
            String jwt = JwtUtils.generateToken(one.getId());
            redisTemplate.opsForValue().set(Constant.USER_PRE + jwt, one);
            return Resp.ok(one).put("token", jwt);
        }

    }

    @GetMapping("/logout")
    public ModelAndView logout(@CookieValue(value = Constant.TOKEN_KEY) String token, HttpServletResponse response){
        ModelAndView modelAndView = new ModelAndView();
        // 清除 redis 值

        // 清除登录标识
        redisTemplate.delete(Constant.USER_PRE + token);
        // 清除记住我标识, 删除 cookie
        Cookie cookie = new Cookie(Constant.REMEMBER_ME, "");
        cookie.setPath("/login");
        cookie.setMaxAge(0);
        response.addCookie(cookie);

        modelAndView.setViewName("redirect:/login");
        return modelAndView;
    }

    @GetMapping("/temp")
    public ModelAndView temp(){
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.setViewName("temp");
        return modelAndView;
    }

    @GetMapping("/register")
    public ModelAndView register(){
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.setViewName("register");
        return modelAndView;
    }

    @PostMapping("/register")
    public Resp doRegister(@RequestBody SysUser sysUser, @CookieValue(value = Constant.TOKEN_KEY, required = false) String token) throws Exception {
        log.info(sysUser.toString());
        // 判断验证码
        Object captcha = redisTemplate.opsForValue().get(Constant.CAPTCHA_PRE + token);
        if (captcha == null){
            return Resp.error("验证码已过期");
        } else if (!captcha.toString().equalsIgnoreCase(sysUser.getCaptcha())){
            return Resp.error("验证码错误");
        }
        // 删除验证码
        redisTemplate.delete(Constant.CAPTCHA_PRE + token);

        // 两次密码输入是否一致
        if (!sysUser.getPassword().equals(sysUser.getRepass())){
            return Resp.error("两次密码输入不一致");
        }

        // 用户编号需要生成
        sysUser.setId(StringUtil.uuid());

        // 密码加密 AES
        sysUser.setPassword(AesUtil.AES_CBC_Encrypt_String(sysUser.getPassword()));

        // 状态 1
        sysUser.setState(1);


        boolean save = sysUserService.save(sysUser);

        if (save){
            return Resp.ok();
        } else {
            return Resp.error("注册失败");
        }
    }

    @GetMapping("/captcha")
    public void captcha(HttpServletRequest request, HttpServletResponse response, @CookieValue(value = Constant.TOKEN_KEY, required = false) String token) throws IOException {
        // png类型
        SpecCaptcha captcha = new SpecCaptcha(130, 48);
        String text = captcha.text();  // 获取验证码的字符
        // 验证码存入 redis
        redisTemplate.opsForValue().set(Constant.CAPTCHA_PRE + token, text, 5, TimeUnit.MINUTES);

        captcha.out(response.getOutputStream());  // 输出图片流
    }


    @GetMapping("/sendEmail")
    public Resp active(String email, HttpServletRequest request){
        // 验证邮箱是否正确
        if (!StringUtils.hasText(email)){
            return Resp.error("邮箱不能为空");
        }
        if (!email.matches("^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\\.[a-zA-Z0-9_-]+)+$")){
            return Resp.error("邮箱格式不正确");
        }
        // 邮箱是否已注册
        QueryWrapper<SysUser> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("email", email);
        long count = sysUserService.count(queryWrapper);
        if (count > 0){
            return Resp.error("邮箱已注册");
        }
        // 发送邮件
        // 上下文路径
        String contextPath = request.getContextPath();
        // 获取当前的域名
        String serverName = request.getServerName();
        // 获取端口号
        int serverPort = request.getServerPort();
        // 协议
        String scheme = request.getScheme();
        // 地址
        String url = scheme + "://" + serverName + ":" + serverPort + contextPath + "/active";
        try{
            sysUserService.sendEmail(email, url);
            // 5分钟有效
            redisTemplate.opsForValue().set(Constant.EMAIL_PRE + email, email, 5, TimeUnit.MINUTES);
            return Resp.ok();
        } catch (Exception e){
            e.printStackTrace();
            return Resp.error("邮件发送失败");
        }
    }

    @GetMapping("/active")
    public ModelAndView active(String email){
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.setViewName("active");
        modelAndView.addObject("email", email);
        return modelAndView;
    }

    @GetMapping("/index")
    public ModelAndView index(){
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.setViewName("index");
        return modelAndView;
    }

    private String userNameType(String username){
        String type = "username";
        if (username.matches(Constant.PATTERN_PHONE)){
            // 手机号
            type = "phone";
        } else if (username.matches(Constant.PATTERN_EMAIL)){
            type = "email";
        }
        return type;
    }

}
